module sdc_ahb_wrap(
           clk,
           reset_n,

           // AHB Slave
           sHADDR,
           sHWDATA,
           sHWRITE,
           sHREADYOUT,
           sHSIZE,
           sHBURST,
           sHSEL,
           sHTRANS,
           sHRDATA,
           sHRESP,
           sHREADY,
           sHPROT,

           // AHB Master
           mHSEL,
           mHSIZE,
           mHRDATA,
           mHRESP,
           mHREADY,
           mHREADYOUT,
           mHWRITE,
           mHBURST,
           mHADDR,
           mHTRANS,
           mHWDATA,
           mHPROT,

           // sdio
           sd_clk,
           sd_cmd,
           sd_dat
       );


localparam [1:0]AHB_TRANS_IDLE = 2'b00,
           AHB_TRANS_BUSY = 2'b01,
           AHB_TRANS_NONSEQ = 2'b10,
           AHB_TRANS_SEQ = 2'b11;

input clk;
input reset_n;

//////////// AHB Slave to Wishbone
input [7:0]     sHADDR;
input [31:0]    sHWDATA;
input           sHWRITE;
input [2:0]     sHSIZE;
input [2:0]     sHBURST;
input           sHSEL;
input [1:0]     sHTRANS;
input           sHREADY;
input [3:0]     sHPROT;

output          sHREADYOUT;
output [31:0]   sHRDATA;
output [1:0]    sHRESP;


wire [31:0]     wb_dat_i;
wire [7:0]      wb_adr_i;
wire [3:0]      wb_sel_i;
wire            wb_we_i;
wire            wb_cyc_i;
wire            wb_stb_i;
wire [31:0]     wb_dat_o;
wire            wb_ack_o;

reg         next_wb_cyc_i;
reg         ito_wb_cyc_i;

reg         next_wb_stb_i;
reg         ito_wb_stb_i;

// 1: 4'b1111, 0: 4'b0000
reg         next_wb_sel_i;
reg         ito_wb_sel_i;

// AHB address & control signal
reg [7:0]   next_wb_adr_i;
reg [7:0]   ito_wb_adr_i;

reg         next_wb_we_i;
reg         ito_wb_we_i;

reg         next_HRESP;
reg         is_HRESP;

assign wb_adr_i = ito_wb_adr_i;
assign wb_we_i = ito_wb_we_i;
assign wb_dat_i = sHWDATA;
assign wb_cyc_i = ito_wb_cyc_i;
assign wb_stb_i = ito_wb_stb_i;
assign wb_sel_i = ito_wb_sel_i ? 4'b1111 : 4'b0000;

assign sHRDATA = wb_dat_o;
assign sHRESP = {1'b0, is_HRESP};
assign sHREADYOUT = wb_stb_i ? wb_ack_o : 1'b1;

always@(*) begin
    next_HRESP = 1'b0;
    next_wb_cyc_i = 1'b0;
    next_wb_stb_i = 1'b0;
    next_wb_we_i = 1'b0;
    next_wb_sel_i = 1'b0;
    next_wb_adr_i = 8'h00;
    if(sHSEL) begin
        if(sHREADY) begin
            if(wb_stb_i & !wb_ack_o) begin
                next_wb_cyc_i = wb_cyc_i;
                next_wb_stb_i = wb_stb_i;
                next_wb_we_i = wb_we_i;
                next_wb_sel_i = wb_sel_i;
                next_wb_adr_i = wb_adr_i;
            end else begin
                if(sHSIZE != 3'b010) begin // size != 32bit)
                    if(sHTRANS == AHB_TRANS_IDLE) begin // No data
                        next_HRESP = 1'b0;
                    end
                    else begin
                        next_HRESP = 1'b1;
                    end
                end
                else begin
                    case (sHTRANS)
                        AHB_TRANS_IDLE: begin
                            // keep zero
                        end
                        AHB_TRANS_BUSY: begin
                            next_wb_cyc_i = 1'b1;
                        end
                        AHB_TRANS_NONSEQ, AHB_TRANS_SEQ: begin
                            next_wb_cyc_i = 1'b1;
                            next_wb_stb_i = 1'b1;
                            next_wb_sel_i = 1'b1;
                            next_wb_adr_i = sHADDR;
                            next_wb_we_i = sHWRITE;
                        end
                    endcase
                end
            end
        end
    end
end

always@(posedge clk or negedge reset_n) begin
    if(!reset_n) begin
        is_HRESP <= 1'b0;
        ito_wb_cyc_i <= 1'b0;
        ito_wb_stb_i <= 1'b0;
        ito_wb_we_i <= 1'b0;
        ito_wb_sel_i <= 1'b0;
        ito_wb_adr_i <= 8'h00;
    end
    else begin
        is_HRESP <= next_HRESP;

        ito_wb_cyc_i <= next_wb_cyc_i;
        ito_wb_stb_i <= next_wb_stb_i;
        ito_wb_we_i <= next_wb_we_i;
        ito_wb_sel_i <= next_wb_sel_i;
        ito_wb_adr_i <= next_wb_adr_i;
    end
end

//////////// Wishbone Master to AHB

input  [31:0]   mHRDATA;
input  [1:0]    mHRESP;
input           mHREADY;

output          mHSEL;
output [2:0]    mHSIZE;
output          mHWRITE;
output [2:0]    mHBURST;
output [31:0]   mHADDR;
output [1:0]    mHTRANS;
output [31:0]   mHWDATA;
output          mHREADYOUT;
output [3:0]    mHPROT;

wire    m_transfer;
wire    m_next_transfer_ack;
reg     m_trans_ack;

reg[31:0] next_mHWDATA;

wire [31:0] m_wb_adr_o;
wire [31:0] m_wb_dat_o;
wire [31:0] m_wb_dat_i;
wire [3:0] m_wb_sel_o;
wire m_wb_we_o;
wire m_wb_ack_i;
wire m_wb_cyc_o;
wire m_wb_stb_o;

assign m_transfer = m_wb_cyc_o & m_wb_stb_o;
assign m_next_transfer_ack = m_transfer & !m_trans_ack;

assign mHSEL = m_transfer;
assign mHSIZE = 3'b010;
assign mHWRITE = m_wb_we_o;
assign mHBURST = 3'b000;
assign mHADDR = m_wb_adr_o;
assign mHWDATA = m_wb_dat_o;
assign mHREADYOUT = 1'b1;
assign mHTRANS = (m_next_transfer_ack) ? AHB_TRANS_NONSEQ : AHB_TRANS_IDLE;

assign m_wb_ack_i = mHREADY & mHSEL & m_trans_ack;
assign m_wb_dat_i = mHRDATA;

always@(posedge clk or negedge reset_n) begin
    if(!reset_n) begin
        m_trans_ack <= 1'b0;
    end else begin
        m_trans_ack <= m_next_transfer_ack;
    end
end

//////////// SDIO
output      sd_clk;
inout       sd_cmd;
inout[3:0]  sd_dat;

wire sd_cmd_dat_i;
wire sd_cmd_out_o;
wire sd_cmd_oe_o;

assign sd_cmd = sd_cmd_oe_o ? sd_cmd_out_o : 1'bz;
assign sd_cmd_dat_i = sd_cmd;

wire[3:0]   sd_dat_dat_i;
wire[3:0]   sd_dat_out_o;
wire        sd_dat_oe_o;

assign sd_dat = sd_dat_oe_o ? sd_dat_out_o : 4'hz;
assign sd_dat_dat_i = sd_dat;

wire sd_clk_o_pad;

//////////// SDCard Controller
sdc_controller sdc(
                   .wb_clk_i(clk),
                   .wb_rst_i(~reset_n),

                   // Slave
                   .wb_dat_i(wb_dat_i),
                   .wb_dat_o(wb_dat_o),
                   .wb_adr_i(wb_adr_i),
                   .wb_sel_i(wb_sel_i),
                   .wb_we_i(wb_we_i),
                   .wb_stb_i(wb_stb_i),
                   .wb_cyc_i(wb_cyc_i),
                   .wb_ack_o(wb_ack_o),

                   // Master
                   .m_wb_adr_o(m_wb_adr_o),
                   .m_wb_dat_o(m_wb_dat_o), // BE to LE
                   .m_wb_dat_i(m_wb_dat_i), // BE to LE
                   .m_wb_sel_o(m_wb_sel_o),
                   .m_wb_we_o(m_wb_we_o),
                   .m_wb_ack_i(m_wb_ack_i),
                   .m_wb_cyc_o(m_wb_cyc_o),
                   .m_wb_stb_o(m_wb_stb_o),

                   // SDIO
                   .sd_cmd_dat_i(sd_cmd_dat_i),
                   .sd_cmd_out_o(sd_cmd_out_o),
                   .sd_cmd_oe_o(sd_cmd_oe_o),
                   .sd_dat_dat_i(sd_dat_dat_i),
                   .sd_dat_out_o(sd_dat_out_o),
                   .sd_dat_oe_o(sd_dat_oe_o),
                   .sd_clk_o_pad(sd_clk),
                   .sd_clk_i_pad(clk)

                   //    .int_cmd(irq_cmd),
                   //    .int_data(irq_data)
               );

endmodule
